package com.zzg.servlet;

import java.io.File;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.nio.channels.FileChannel;
import java.util.List;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadBase;
import org.apache.commons.fileupload.ProgressListener;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;

public class WebUploadHandler extends HttpServlet {

	public WebUploadHandler() {
		super();
	}

	public void destroy() {
		super.destroy();
	}
	
	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		this.doPost(request, response);
	}

	public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		System.out.println("------------------------------------------------------WebUploadHandler开始处理WebUploader上传的文件------------------------------------------------------");
		
		//得到上传文件的保存目录，将上传的文件存放于WEB-INF目录下，不允许外界直接访问，保证上传文件的安全
		String savePath = this.getServletContext().getRealPath("/WEB-INF/upload/");
		//上传时生成的临时文件和备份文件的保存目录
		String tempPath = this.getServletContext().getRealPath("/WEB-INF/upload/temp/");
		File tmpFile = new File(tempPath);
		if (!tmpFile.exists()) {
			//创建临时目录
			tmpFile.mkdirs();
		}
		
		try{
			//使用Apache文件上传组件处理文件上传步骤：
			//1、创建一个DiskFileItemFactory工厂
			DiskFileItemFactory factory = new DiskFileItemFactory();
			//设置工厂的缓冲区的大小，当上传的文件大小超过缓冲区的大小时，就会生成一个临时文件存放到指定的临时目录当中。
			factory.setSizeThreshold(1024*1000);//设置缓冲区的大小为1000KB，如果不指定，那么缓冲区的大小默认是10KB
			//设置上传时生成的临时文件的保存目录
			factory.setRepository(tmpFile);
			//2、创建一个文件上传解析器
			ServletFileUpload upload = new ServletFileUpload(factory);
			//监听文件上传进度
			upload.setProgressListener(new ProgressListener(){
				public void update(long pBytesRead, long pContentLength, int arg2) {
					System.out.println("文件大小为：" + pContentLength + ",当前已处理：" + pBytesRead);
					/**
					 * 	文件大小为：14608,当前已处理：4096
	    	  			 *	文件大小为：14608,当前已处理：7367
	    	  			 *	文件大小为：14608,当前已处理：11419
	      			 *	文件大小为：14608,当前已处理：14608
					 */
				}
			});
			//解决上传文件名的中文乱码
			upload.setHeaderEncoding("UTF-8"); 
			//3、判断提交上来的数据是否是上传表单的数据，即是否是multipart/form-data
			if(!ServletFileUpload.isMultipartContent(request)){
				//按照传统方式获取数据
				return;
			}
			
			//设置上传单个文件的大小的最大值，目前是设置为1024*1024*50字节，也就是20MB
			upload.setFileSizeMax(1024*1024*20);
			//设置上传文件总量的最大值，最大值=同时上传的多个文件的大小的最大值的和，目前设置为200MB
			upload.setSizeMax(1024*1024*20*10);
			//4、使用ServletFileUpload解析器解析上传数据，解析结果返回的是一个List<FileItem>集合，每一个FileItem对应一个Form表单的输入项
			List<FileItem> list = upload.parseRequest(request);
			for(FileItem item : list){
				//如果fileitem中封装的是普通输入项的数据
				if(item.isFormField()){
					String name = item.getFieldName();	//参数名
					//解决普通输入项的数据的中文乱码问题
					String value = item.getString("UTF-8");	//参数值
					//value = new String(value.getBytes("iso8859-1"),"UTF-8");
					System.out.println("参数名=" + name + "，参数值=" + value);
				}else{//如果fileitem中封装的是上传文件
					//得到上传的文件名称，
					String filename = item.getName();
					//System.out.println("filename=" + filename);
					if(filename==null || filename.trim().equals("")){
						System.out.println("没有选择上传的文件");
						continue;
					}
					//注意：不同的浏览器提交的文件名是不一样的，有些浏览器提交上来的文件名是带有路径的，如： c:\a\b\1.txt，而有些只是单纯的文件名，如：1.txt
					//处理获取到的上传文件的文件名的路径部分，只保留文件名部分
					filename = filename.substring(filename.lastIndexOf("\\")+1);
					//得到上传文件的扩展名
					String fileExtName = filename.substring(filename.lastIndexOf(".")+1);
					//如果需要限制上传的文件类型，那么可以通过文件的扩展名来判断上传的文件类型是否合法
					//System.out.println("上传的文件的扩展名是："+fileExtName);
					//获取item中的上传文件的输入流
					InputStream in = item.getInputStream();
					//得到文件保存的名称
					//String saveFilename = Math.random()+filename;
					String saveFilename = filename;
					//得到文件的保存目录
					File file = new File(savePath);
					//如果目录不存在
					if(!file.exists()){
						//创建目录
						file.mkdirs();
					}
					
					//将上传的文件保存到临时目录
					File tempOriginalFile=new File(tmpFile,saveFilename);
					//创建一个文件输出流
					FileOutputStream fos = new FileOutputStream(tempOriginalFile);
					//创建一个缓冲区
					byte buffer[] = new byte[1024*1024];
					//判断输入流中的数据是否已经读完的标识        
					int len = 0;
					//循环将输入流读入到缓冲区当中，(len=in.read(buffer))>0就表示in里面还有数据
					while((len=in.read(buffer))>0){
						//使用FileOutputStream输出流将缓冲区的数据写入到临时目录中
						fos.write(buffer, 0, len);
					}
					
					String apkUrl = tempOriginalFile.toString();	//上传的apk所在临时目录
			        
		        	File originalFile=new File(file,saveFilename);	//最终保存文件的路径
		        	
					copyFileUsingFileChannels(tempOriginalFile, originalFile);	//将新上传的文件从临时目录拷贝到目标文件夹
					
					//关闭输入流
					in.close();
					//关闭输出流
					fos.close();        
					//删除处理文件上传时生成的临时文件
					item.delete();
				}
			}
		}catch (Exception e) {
			System.out.println("文件上传失败！");
			e.printStackTrace();
		}finally{
			//操作完成后删除临时备份文件夹
			deleteDirectory(tempPath);
		}
		System.out.println("------------------------------------------------------WebUploadHandler结束处理WebUploader上传的文件------------------------------------------------------");
	}

	/**
	 * @method copyFileUsingFileChannels
	 * @description 复制文件
	 * @author LeonZhang
	 * @date: 2017-6-28 
	 * @param source 源文件所在路径
	 * @param dest 目的路径
	 * @throws IOException
	 */
	public void copyFileUsingFileChannels(File source, File dest) throws IOException {  
	    FileChannel inputChannel = null;  
	    FileChannel outputChannel = null;  
	  try {
	    inputChannel = new FileInputStream(source).getChannel();
	    outputChannel = new FileOutputStream(dest).getChannel();
	    //System.out.println("---------开始执行文件备份操作---------");
	    outputChannel.transferFrom(inputChannel, 0, inputChannel.size());
	  } finally {
		if(inputChannel!=null){
			inputChannel.close();
		}
	    if(outputChannel!=null){
	    	outputChannel.close();
	    }
	  }
	}
	
	boolean flag;
	
	/** 
	 * 删除目录（文件夹）以及目录下的文件 
	 * @param   sPath 被删除目录的文件路径 
	 * @return  目录删除成功返回true，否则返回false 
	 */  
	public boolean deleteDirectory(String sPath) {  
	    //如果sPath不以文件分隔符结尾，自动添加文件分隔符  
	    if (!sPath.endsWith(File.separator)) {  
	        sPath = sPath + File.separator;  
	    }  
	    File dirFile = new File(sPath);  
	    //如果dir对应的文件不存在，或者不是一个目录，则退出  
	    if (!dirFile.exists() || !dirFile.isDirectory()) {  
	        return false;  
	    }  
	    flag = true;  
	    //删除文件夹下的所有文件(包括子目录)  
	    File[] files = dirFile.listFiles();  
	    for (int i = 0; i < files.length; i++) {  
	        //删除子文件  
	        if (files[i].isFile()) {  
	            flag = deleteFile(files[i].getAbsolutePath());  
	            if (!flag) break;  
	        } //删除子目录  
	        else {  
	            flag = deleteDirectory(files[i].getAbsolutePath());  
	            if (!flag) break;  
	        }  
	    }  
	    if (!flag) return false;  
	    //删除当前目录  
	    if (dirFile.delete()) {  
	        return true;  
	    } else {  
	        return false;  
	    }  
	} 
	
	/** 
	 * @description 删除单个文件 
	 * @param   sPath    被删除文件的文件名 
	 * @return 单个文件删除成功返回true，否则返回false 
	 */  
	public boolean deleteFile(String sPath) {  
	    flag = false;  
	    File file = new File(sPath);  
	    // 路径为文件且不为空则进行删除  
	    if (file.isFile() && file.exists()) {  
	        file.delete();  
	        flag = true;  
	    }  
	    return flag;  
	}
	
	public void init() throws ServletException {
		
	}

}
